package com.pig4cloud.pig.ads.service.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.util.ArrayUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dy.yunying.api.resp.ChannelManageRes;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.api.client.util.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.pig4cloud.pig.ads.clickhouse3399.mapper.AdAudienceMapper;
import com.pig4cloud.pig.ads.config.SdkProperties;
import com.pig4cloud.pig.ads.gdt.service.GdtCustomAudiencesService;
import com.pig4cloud.pig.ads.gdt.service.impl.GdtAdgroupTempServiceImpl;
import com.pig4cloud.pig.ads.pig.mapper.AdPlanMapper;
import com.pig4cloud.pig.ads.pig.mapper.AdPromotionMapper;
import com.pig4cloud.pig.ads.pig.mapper.gdt.GdtAdgroupMapper;
import com.pig4cloud.pig.ads.pig.mapper.ks.KsUnitMapper;
import com.pig4cloud.pig.ads.service.*;
import com.pig4cloud.pig.ads.service.bd.BdAdgroupService;
import com.pig4cloud.pig.ads.service.kafka.CommonKafkaService;
import com.pig4cloud.pig.ads.utils.DateUtils;
import com.pig4cloud.pig.ads.utils.OEHttpUtils;
import com.pig4cloud.pig.api.dto.*;
import com.pig4cloud.pig.api.entity.*;
import com.pig4cloud.pig.api.entity.bd.BdAdgroup;
import com.pig4cloud.pig.api.entity.ks.KsUnit;
import com.pig4cloud.pig.api.enums.*;
import com.pig4cloud.pig.api.gdt.entity.GdtAdgroup;
import com.pig4cloud.pig.api.gdt.entity.GdtCustomAudiences;
import com.pig4cloud.pig.api.util.Constants;
import com.pig4cloud.pig.api.util.JsonUtil;
import com.pig4cloud.pig.api.util.MapUtils;
import com.pig4cloud.pig.api.vo.AdPtypeVo;
import com.pig4cloud.pig.api.vo.MaterialVo;
import com.pig4cloud.pig.api.vo.PlanGdtAttrAnalyseReportVo;
import com.pig4cloud.pig.common.core.constant.enums.PlatformTypeEnum;
import com.pig4cloud.pig.common.core.exception.BusinessException;
import com.pig4cloud.pig.common.core.util.DateUtil;
import com.pig4cloud.pig.common.core.util.R;
import io.swagger.models.auth.In;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 广告计划 服务实现类
 *
 * @author hma
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AdvPlanServiceImpl extends ServiceImpl<AdPlanMapper, AdPlan> implements AdvPlanService {
	private static Logger logger = LoggerFactory.getLogger(AdvPlanServiceImpl.class);

	@Resource
	private AdvCampaignService advCampaignService;
	@Resource
	private TtAccesstokenService ttAccesstokenService;
	@Autowired
	private AudiencePackageService audiencePackageService;
	@Autowired
	private AdvCampaignServiceImpl advCampaignServiceImpl;
	@Autowired
	private final ConvertTrackService convertTrackService;
	@Autowired
	private final StringRedisTemplate stringRedisTemplate;
	@Autowired
	private final TtCustomAudienceService ttCustomAudienceService;
	@Autowired
	GdtCustomAudiencesService gdtCustomAudiencesService;
	@Autowired
	private final AdActionInterestService adActionInterestService;
	@Autowired
	private final GdtActionInterestService gdtActionInterestService;
	@Autowired
	private GdtAdgroupTempServiceImpl gdtAdgroupTempService;
	private final AdAudienceMapper adAudienceMapper;
	private final AdAssetsTrackService adAssetsTrackService;
	private final BdAdgroupService bdAdgroupService;
	@Autowired
	private CommonKafkaService commonKafkaService;

	private static final String TT_PACK_THIRDID_NAME_KEY = "TT_PACK_THIRDID_NAME_KEY";
	private static final String GDT_PACK_THIRDID_NAME_KEY = "GDT_PACK_THIRDID_NAME_KEY";
	private static final String TT_ACTION_INTEREST_THIRDID_NAME_KEY = "TT_ACTION_INTEREST_THIRDID_NAME_KEY";
	private static final String GDT_ACTION_INTEREST_THIRDID_NAME_KEY = "GDT_ACTION_INTEREST_THIRDID_NAME_KEY";
	private static boolean TT_PACK_THIRDID_NAME_KEY_LOADED = false;
	private static boolean GDT_PACK_THIRDID_NAME_KEY_LOADED = false;
	private static boolean TT_ACTION_INTEREST_THIRDID_NAME_KEY_LOADED = false;
	private static boolean GDT_ACTION_INTEREST_THIRDID_NAME_KEY_LOADED = false;
	private final DateTimeFormatter fmTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

	@Autowired
	private GdtAdgroupMapper gdtAdgroupMapper;

	@Autowired
	private KsUnitMapper ksUnitMapper;

	@Autowired
	private AdPromotionMapper adPromotionMapper;

	@Value("${ad_third_url}")
	private String adThirdUrl;
	@Value("${adv_plan_url}")
	private String advPlanUrl;
	@Value("${adv_plan_create_url}")
	private String advPlanCreateUrl;
	@Value("${gdt_action_interest_intention_cache_time:5}")
	private Long dictCacheTime;

	@Value("${dongxin_kafka_topic}")
	private String DONGXIN_KAFKA_TOPIC;

	@Value("${dongxin_event_name}")
	private String DONGXIN_EVENT_NAME;

	@Value("${spring.profiles.active}")
	private String profiles;

	@Autowired
	private SdkProperties sdkProperties;

	/**
	 * 查询广告创意报表数据
	 *
	 * @param campaignDto
	 * @return
	 */

	@Override
	public R getAdvPlanStatistic(CampaignDto campaignDto) {
		campaignDto.setType(StatusEnum.TYPE_TWO.getStatus());
		campaignDto.setAdType(StatusEnum.AD_TYPE_ONE.getStatus());
		return advCampaignService.getAdvStatistic(campaignDto);
	}

	@Override
	public R updatePlanStatus(AdvertiserDto planDto) {
		if (null == planDto) {
			return R.failed("参数为空");
		}
		if (null == planDto.getAdvertiserId()) {
			return R.failed("广告账号id不允许为空");
		}
		if (null == planDto.getAdId()) {
			return R.failed("广告计划id不允许为空");
		}
		if (null == planDto.getOptStatus()) {
			return R.failed("操作状态不允许为空");
		}
		R r = advCampaignService.updateThirdData(planDto, StatusEnum.TYPE_TWO.getStatus());
		if (r.getCode() == 0) {
			String status = null;
			if (StringUtils.equals(planDto.getOptStatus(), "enable")) {
				status = "AD_STATUS_ENABLE";
			} else if (StringUtils.equals(planDto.getOptStatus(), "disable")) {
				status = "AD_STATUS_DISABLE";
			}
			baseMapper.updateById(new AdPlan(planDto.getAdId(), status));
			return R.ok();
		} else {
			return r;
		}

	}

	/**
	 * 创建广告计划
	 *
	 * @param adPlanCreateDto
	 * @return
	 */
	@Override
	public AdPlanCreateDto createAdvPlan(AdPlanCreateDto adPlanCreateDto) {
		// 调用头条创建广告计划
		// 返回对应的广告计划id
		// 广告计划名称不允许重复
		// 字段不限的时候 设置值为空，不传值------库里面的数据为空 当不限的时候
		try {
			//基础check
			this.baseCheck(adPlanCreateDto);
			String adName = adPlanCreateDto.getAdName();
			Long advertiserId = adPlanCreateDto.getAdvertiserId();

			//业务check
			AdPlanDto adPlanDto = new AdPlanDto();
			adPlanDto.setAdvertiserId(String.valueOf(advertiserId));
			adPlanDto.setCampaignId(adPlanCreateDto.getCampaignId());
			adPlanDto.setAdName(adName);
			List<AdPlan> adPlanList = baseMapper.selectAdPlanList(adPlanDto);
			if (CollectionUtils.isNotEmpty(adPlanList)) {
				throw new BusinessException(11, "该推广组下面的广告名称重复了");
			}
			//构建请求参数MAP
			Map<String, Object> paramMap = this.buildParamMap(adPlanCreateDto);

			String adId = createThirdPlanOrCreative(paramMap, "createAdvPlan", advPlanCreateUrl, advertiserId.toString(), StatusEnum.TYPE_TWO.getStatus());
			if (StringUtils.isBlank(adId)) {
				throw new BusinessException(11, "创建广告计划异常");
			}
			adPlanCreateDto.setAdId(Long.parseLong(adId));
		} catch (Exception e) {
			logger.error("createAdvPlan is error", e);
			e.printStackTrace();
			throw new BusinessException(11, e.getMessage());
		} finally {
			// 判空 避免发生异常 finally执行时ad_ptype 有重复记录
			if (null != adPlanCreateDto.getAdId()) {
				//防止测试环境创建广告时上报的数据中心线上环境，故区分clickId便于数据清理
				String clickId = "has_cost_but_no_click_default_value";
				if (profiles.contains("test") || profiles.contains("stg")) {
					clickId = "TEST_has_cost_but_no_click_default_value";
				}
				//更新转化关联的广告计划数量
				//20220409 联调转化更新为事件后不需要此操作
//				convertTrackService.increaseAdPlanCouont(adPlanCreateDto.getConvertId());
				//创建广告计划成功后，需要初始化ad_ptype表，解决有消耗无点击关联不到渠道的问题
				AdPTypeDTO dto = new AdPTypeDTO(Integer.parseInt(PlatformTypeEnum.TT.getValue()),
						clickId,LocalDateTime.now().format(fmTime),999);

				AdAssetsTrack adAssetsTrack = adAssetsTrackService.getOne(Wrappers.<AdAssetsTrack>lambdaQuery()
						.eq(AdAssetsTrack::getMediaCode,PlatformTypeEnum.TT.getValue())
						.eq(AdAssetsTrack::getAdvertiserId,adPlanCreateDto.getAdvertiserId())
						.eq(AdAssetsTrack::getTrackUrlGroupId,adPlanCreateDto.getTrackGroupId())
						.eq(AdAssetsTrack::getDeleted,0)
						.last("LIMIT 1"));
				if (Objects.nonNull(adAssetsTrack) && StringUtils.isNotBlank(adAssetsTrack.getChl())){
					//联调转化表没有存储分包ID，暂从下载链接中截取
					// 头条广告下载链接已改变必须为头条官方链接
					// 如：https://apps.bytesfield.com/download/extend/cur/81569d88089d74a539df39eab0bc05acb07421ad/54x219x96x828
					//54x219x96x828  ==> 主渠道x子渠道x子游戏x分包序号
					String appchl = adAssetsTrack.getChl();
					String[] chlArray = appchl.split("x");
					String parentChl = chlArray[0];
					String chl = chlArray[0].concat("x").concat(chlArray[1]);
					Integer gameId = Integer.parseInt(chlArray[2]);
					dto.setAdaccount(String.valueOf(adPlanCreateDto.getAdvertiserId()));
					dto.setAdid(String.valueOf(adPlanCreateDto.getAdId()));
					dto.setPtype(adAssetsTrack.getChl());
					dto.setAppchl(adAssetsTrack.getChl());
					dto.setGameid(Objects.nonNull(adAssetsTrack.getGameId()) ? adAssetsTrack.getGameId().intValue() : gameId);
					dto.setParentchl(parentChl);
					dto.setChl(chl);
					//新创建的广告计划不存在重复
					//AdPtypeVo ptypeVo = adAudienceMapper.selectAdPTypeByAdId(dto);
					adAudienceMapper.insertAdPType(dto);
					logger.info("初始化ad_ptype成功");
				}else{
					logger.info(">>>>>>adAssetsTrack对象数据：{}",JSON.toJSONString(adAssetsTrack));
					logger.info(">>>>>>未获取到监测链接组信息或分包信息");
				}

				//也需要上报给数据中的ad_ptype表
				try {
					//上报给动心sdk
					List<AdPTypeDTO> list = Lists.newArrayList();
					list.add(dto);
					Map<String, Object> map = new HashMap<>();
					map.put(Constants.DONGXIN_DATA, JSON.toJSONString(list));
					map.put(Constants.DATA_TYPE_DONGXIN_EVENTNAME, DONGXIN_EVENT_NAME);
					logger.info("ad_ptype上报数据中心{}", JSON.toJSONString(dto));
					//不直接使用kafkaTemplate,使用commonKafkaService异步调用，不能阻塞创建广告流程
					commonKafkaService.send(DONGXIN_KAFKA_TOPIC, map);
				} catch (Exception e) {
					logger.info("ad_ptype上报数据中心失败,失败数据{}", JSON.toJSONString(dto));
					e.printStackTrace();
				}
			}
		}
		return adPlanCreateDto;
	}

	private Map<String, Object> buildParamMap(AdPlanCreateDto adPlanCreateDto) throws JsonProcessingException {
		// fastJson 不会过滤 ""
		log.info("adPlanCreateDto2=====>{}", JSON.toJSONString(adPlanCreateDto));
		// 对于不打算传的字段，不要传“”或者null，传了头条会校验
		// Include.NON_NULL 为null不参与序列化
		String paramJson = JsonUtil.toUnderlineJSONString(adPlanCreateDto);
		log.info("创建广告计划，监测组ID：{}，paramJson=====>{}", adPlanCreateDto.getTrackGroupId(),paramJson);
		// 除掉为空或者空字符串字段
		Map<String, Object> paramMap = JsonUtil.parseJSON2Map(paramJson);
		log.info("创建广告计划，监测组ID：{}，paramMap=====>{}", adPlanCreateDto.getTrackGroupId(),JSON.toJSONString(paramMap));
		//处理名称与头条接口不一致的情况
		if (null != paramMap.get("ad_name")) {
			paramMap.put("name", paramMap.get("ad_name"));
		}
		// 资产信息
		if (null != paramMap.get("asset_ids")) {
			String assetIds = (String) paramMap.get("asset_ids");
			paramMap.put("asset_ids",  Arrays.stream(assetIds.split(",")).filter(v -> StringUtils.isNotBlank(v)).mapToLong(Long::valueOf).toArray());
		}

		if (null != paramMap.get("convert_type")) {
			paramMap.put("external_action", paramMap.get("convert_type"));
		}

		if (null != paramMap.get("track_group_type")) {
			paramMap.put("track_url_group_type", paramMap.get("track_group_type"));
		}

		if (null != paramMap.get("track_group_id")) {
			paramMap.put("track_url_group_id", paramMap.get("track_group_id"));
		}

		if (null != paramMap.get("down_package")) {
			paramMap.put("package", paramMap.get("down_package"));
		}
		if (null != paramMap.get("audience_id")) {
			paramMap.put("audience_package_id", paramMap.get("audience_id"));
		}
		//deep_external_action目前看来不能传了DEEP_BID_DEFAULT或""
		String deepExternalAction = (String) paramMap.get("deep_external_action");
		if (StringUtils.isBlank(deepExternalAction) || "DEEP_BID_DEFAULT".equals(deepExternalAction)) {
			paramMap.remove("deep_external_action");
		}

		//inventory_type、action_track_url 拉取都是String接收的是数据库存储的都是JSON类型的字符串
		//inventory_type=["aa","bb"]  新建广告是按逗号分割的，已在getJsonArrString转为JSON字符串
		// 正式表存储的是转为JSON的字符串
		//v2.4.2 新增广告位大类
		// inventory_type、smart_inventory 二选一，设置smart_inventory时会忽略inventory_type 实际复制时测试不能传inventory_type,否则报非法的广告位组合
		this.jsonToObject(paramMap, "inventory_type", String[].class);
		this.jsonToObject(paramMap, "action_track_url", String[].class);

		// add chengang 20210712 设置行为兴趣
		if (null != paramMap.get("interest_action_mode")) {
			//兼容前端各种写法
			if (StringUtils.equals(String.valueOf(paramMap.get("interest_action_mode")), "CUSTOM")
					|| StringUtils.equals(String.valueOf(paramMap.get("interest_action_mode")), "customize")) {
				//正式表和临时表存储的格式不一样，需要做额外处理
				//正式表存储的是接口所需格式 如：[2,4,6,11,16,20]
				if (!adPlanCreateDto.getCopyFlag()) {
					//行为场景,数据逗号分割需转数组
					if (null != paramMap.get("action_scene")) {
						String actionScene = String.valueOf(paramMap.get("action_scene"));
						List<String> tmpArray = (List) JSONArray.parse(actionScene);
						paramMap.put("action_scene", tmpArray.stream().filter(v -> StringUtils.isNotBlank(v)).toArray());
					}
					//用户发生行为天数
					//String paramJson = JsonUtil.toUnderlineJSONString(adPlanCreateDto); 已转换
					if (null != paramMap.get("action_days")) {
						String actionDays = String.valueOf(paramMap.get("action_days"));
						paramMap.put("action_days", Integer.parseInt(actionDays));
					}
					//行为类目词
					if (null != paramMap.get("action_categories")) {
						String actionCategories = String.valueOf(paramMap.get("action_categories"));
						//actionCategories = ["123","124"]
						//JSON.parseObject(actionCategories,String[].class);
						List<String> tmpArray = (List) JSONArray.parse(actionCategories);
						//过滤""值
						// mapToInt - > mapToLong 头条的给的值超过了Int的范围
						paramMap.put("action_categories", tmpArray.stream().filter(v -> StringUtils.isNotBlank(v)).mapToLong(Long::valueOf).toArray());
					}
					//行为关键词
					if (null != paramMap.get("action_words")) {
						String actionWords = String.valueOf(paramMap.get("action_words"));
						List<String> tmpArray = (List) JSONArray.parse(actionWords);
						paramMap.put("action_words", tmpArray.stream().filter(v -> StringUtils.isNotBlank(v)).mapToLong(Long::valueOf).toArray());
					}
					//兴趣类目词
					if (null != paramMap.get("interest_categories")) {
						String interestCategories = String.valueOf(paramMap.get("interest_categories"));
						List<String> tmpArray = (List) JSONArray.parse(interestCategories);
						paramMap.put("interest_categories", tmpArray.stream().filter(v -> StringUtils.isNotBlank(v)).mapToLong(Long::valueOf).toArray());
					}
					//兴趣关键词
					if (null != paramMap.get("interest_words")) {
						String interestWords = String.valueOf(paramMap.get("interest_words"));
						List<String> tmpArray = (List) JSONArray.parse(interestWords);
						paramMap.put("interest_words", tmpArray.stream().filter(v -> StringUtils.isNotBlank(v)).mapToLong(Long::valueOf).toArray());
					}
				} else {
					// 复制的情况
					//行为场景,数据逗号分割需转数组
					if (null != paramMap.get("action_scene")) {
						String actionScene = String.valueOf(paramMap.get("action_scene"));
						JSONArray actionSceneArray = JSON.parseArray(actionScene);
						String[] value = actionSceneArray.toArray(new String[actionSceneArray.size()]);
						paramMap.put("action_scene", value);
					}
					//用户发生行为天数
					//String paramJson = JsonUtil.toUnderlineJSONString(adPlanCreateDto); 已转换
					if (null != paramMap.get("action_days")) {
						String actionDays = String.valueOf(paramMap.get("action_days"));
						paramMap.put("action_days", Integer.parseInt(actionDays));
					}
					//行为类目词
					if (null != paramMap.get("action_categories")) {
						// "[1,2,3,4]"
						String actionCategories = String.valueOf(paramMap.get("action_categories"));
						paramMap.put("action_categories", JSON.parseObject(actionCategories, Long[].class));
					}
					//行为关键词
					if (null != paramMap.get("action_words")) {
						String actionWords = String.valueOf(paramMap.get("action_words"));
//						paramMap.put("action_words",JSON.parseArray(actionWords).toArray());
						paramMap.put("action_words", JSON.parseObject(actionWords, Long[].class));
					}
					//兴趣类目词
					if (null != paramMap.get("interest_categories")) {
						String interestCategories = String.valueOf(paramMap.get("interest_categories"));
						paramMap.put("interest_categories", JSON.parseObject(interestCategories, Long[].class));
					}
					//兴趣关键词
					if (null != paramMap.get("interest_words")) {
						String interestWords = String.valueOf(paramMap.get("interest_words"));
						paramMap.put("interest_words", JSON.parseObject(interestWords, Long[].class));
					}
				}
			}
		}

		// 前端不修改的情况下移除新接口不需要的字段
		this.removeKeys(paramMap);
		return paramMap;
	}

	private void removeKeys(Map<String, Object> paramMap) {
		paramMap.remove("external_url");
		paramMap.remove("device_brand_type");
		paramMap.remove("launch_price_type");
		paramMap.remove("copy_flag");
	}

	private void jsonToObject(Map<String, Object> paramMap, String key, Class clazz) {
		// "[1,2,3,4]" || "["aa","bb"]"
		if (paramMap.get(key) != null) {
			String value = String.valueOf(paramMap.get(key));
			paramMap.put(key, JSON.parseObject(value, clazz));
		}
	}

	private void baseCheck(AdPlanCreateDto adPlanCreateDto) {

		//复制时删除原来的广告计划ID，避免ad_ptype 有重复记录
		if (adPlanCreateDto.getCopyFlag()) {
			adPlanCreateDto.setAdId(null);
		}

		if (StringUtils.isBlank(adPlanCreateDto.getAdName())) {
			throw new BusinessException(11, "广告名称不允许为空");
		}

		//校验广告大类
		if (StringUtils.isBlank(adPlanCreateDto.getInventoryCatalog())) {
			throw new BusinessException(1001, "广告位大类不允许为空");
		}
		if (InventoryCatalogEnum.MANUAL.getValue().equals(adPlanCreateDto.getInventoryCatalog())
				&& StringUtils.isBlank(adPlanCreateDto.getInventoryType())) {
			throw new BusinessException(1002, "广告投放位置（首选媒体）不允许为空");
		}
		if (InventoryCatalogEnum.SCENE.getValue().equals(adPlanCreateDto.getInventoryCatalog())
				&& StringUtils.isBlank(adPlanCreateDto.getSceneInventory())) {
			throw new BusinessException(1002, "首选场景广告位不允许为空");
		}
		// inventory_type、smart_inventory 二选一，设置smart_inventory时会忽略inventory_type
		if (InventoryCatalogEnum.SMART.getValue().equals(adPlanCreateDto.getInventoryCatalog())
			|| InventoryCatalogEnum.UNIVERSAL_SMART.getValue().equals(adPlanCreateDto.getInventoryCatalog())) {
			//当广告位大类 = SMART优选广告位 时，头条返回了inventory_type 会导致复制广告时提示：广告位组合非法
			// 数据库先存储，调用接口时不传
			adPlanCreateDto.setInventoryType(null);
		} else {
			//smart_inventory、scene_inventory 同时传 广告位组合非法
			adPlanCreateDto.setSmartInventory(null);
		}

		// 转化目标
		String convertType = adPlanCreateDto.getConvertType();
		// 监测链接组ID
		Long trackGroupId = adPlanCreateDto.getTrackGroupId();
		// 监测链接组类型
		String trackGroupType = adPlanCreateDto.getTrackGroupType();
		// 资产ID
		String assetIds = adPlanCreateDto.getAssetIds();

		//付费-无的场景，存在每次付费的深度优化方式
		if (StringUtils.isBlank(adPlanCreateDto.getDeepExternalAction()) && !"AD_CONVERT_TYPE_PAY".equals(convertType)) {
			adPlanCreateDto.setDeepBidType(null);
		}

		if (StringUtils.isBlank(assetIds)) {
			throw new BusinessException(11, "资产ID不能为空");
		}

		if (StringUtils.isBlank(convertType)) {
			throw new BusinessException(11, "转化目标不能为空");
		}

		if (trackGroupId == null) {
			throw new BusinessException(11, "监测链接组ID不能为空");
		}

		if (StringUtils.isBlank(trackGroupType)) {
			throw new BusinessException(11, "监测链接组类型不能为空");
		}

		// 预算与出价
		// 校验 投放时间
		if (StringUtils.equals(adPlanCreateDto.getScheduleType(), "SCHEDULE_START_END")) {
			if (StringUtils.isBlank(adPlanCreateDto.getStartTime()) || StringUtils.isBlank(adPlanCreateDto.getEndTime())) {
				throw new BusinessException(11, "广告计划设置投放时间段，开始时间和结束时间不允许为空");
			}
		}

		//总预算模式, 从今天起长期投放，开始必须设置开始时间
		Date now = new Date();
		if (StringUtils.equals(adPlanCreateDto.getBudgetMode(), "BUDGET_MODE_TOTAL") && StringUtils.equals(adPlanCreateDto.getScheduleType(), "SCHEDULE_FROM_NOW") && StringUtils.isBlank(adPlanCreateDto.getStartTime())) {
			adPlanCreateDto.setStartTime(DateUtils.dateToString(now, "yyyy-MM-dd HH:mm"));
		}

		if (StringUtils.equals(adPlanCreateDto.getPricing(), "PRICING_OCPM")) {
			//	convert_id	条件必填	number	转化目标， 当出价方式为"OCPM"时必填，当出价方式为"CPC"和"CPM"时非必填。
			if (null == adPlanCreateDto.getConvertType()) {
				throw new BusinessException(11, "广告计划出价方式为OCPM,转换目标不能为空");
			}
		}
		if (null != adPlanCreateDto.getCpaBid() && adPlanCreateDto.getCpaBid().compareTo(new BigDecimal(0)) == 1) {
			adPlanCreateDto.setAdjustCpa("1");
		}

		//新建定向的情况
		if (adPlanCreateDto.getAudienceId() == null) {
			//当定向包主键为空 ，判断新建定向包的参数
			if (StringUtils.equals(adPlanCreateDto.getDownloadType(), "DOWNLOAD_URL")) {
				//下载链接
				if (StringUtils.isBlank(adPlanCreateDto.getAppType())) {
					throw new BusinessException(11, "广告计划下载的应用类型appType不能为空");
				}
				if (StringUtils.isBlank(adPlanCreateDto.getDownPackage())) {
					throw new BusinessException(11, "广告计划下载的应用包名downPackage不能为空");
				}
				if (StringUtils.isBlank(adPlanCreateDto.getDownloadUrl())) {
					throw new BusinessException(11, "广告计划下载的下载链接downloadUrl不能为空");
				}
			} else if (StringUtils.equals(adPlanCreateDto.getDownloadType(), "EXTERNAL_URL")) {
				//落地页
				if (StringUtils.isBlank(adPlanCreateDto.getExternalUrl())) {
					throw new BusinessException(11, "广告计划落地页链接externalUrl不能为空");
				}
			}
			//非复制才增加[]
			//广告数据报表按广告计划展示时可以复制广告 /plan/copyIt 此时copyFlag = true
			if (!adPlanCreateDto.getCopyFlag()) {
				adPlanCreateDto = getJsonArrString(adPlanCreateDto);
				adPlanCreateDto = dealRetargetingTags(adPlanCreateDto);
				//复制读取正式表，是存在[]，不需要处理
			} else {
				//复制的 inventoryType 已经是含 [] 的字符串了
				//复制时监测链接取的是目标转化的监测链接，因临时表和正式表存储格式不一致，故需要转JSONSting！
				// 20220408 使用监测链接组
//				adPlanCreateDto.setActionTrackUrl(JSONObject.toJSONString(filterNull(adPlanCreateDto.getActionTrackUrl().split(","))));
				//复制的时候，涉及到人群包权限的问题，这里直接设置为null
				adPlanCreateDto.setRetargetingTagsInclude(null);
				adPlanCreateDto.setRetargetingTagsExclude(null);
			}
			//存在定向id，从定向包获取定向和排除定向
		} else {
			log.info("=====>存在定向id" + adPlanCreateDto.getAudienceId());
			//定向包和临时表的定向人群和排除人群存储格式不包含[]; 正式表的定向人群和排除人群存储格式包含[];
			//选择已有定向包时，获取已有定向包的定向人群和排除人群发送接口
			AudiencePackage audiencePackage = audiencePackageService.getOne(Wrappers.<AudiencePackage>query().lambda().eq(AudiencePackage::getIdAdPlatform, adPlanCreateDto.getAudienceId()));
			if (audiencePackage == null) {
				throw new BusinessException(11, "定向包id=" + adPlanCreateDto.getAudienceId() + "在本地不存在");
			}

			//选择已有定向包创建计划是只设置了人群包
			//这里还不存在[]  audiencePackage.getRetargetingTags() 数据库中取出来是纯字符串
			adPlanCreateDto.setRetargetingTagsInclude(audiencePackage.getRetargetingTags());
			adPlanCreateDto.setRetargetingTagsExclude(audiencePackage.getRetargetingTagsExclude());

			//复制的时候，需要取出该定向包的详细信息,然后将定向包置null（目前还不支持定向包的复制）
			if (adPlanCreateDto.getCopyFlag()) {
				AudienceSnake audience = new AudienceSnake();
				BeanUtils.copyProperties(audiencePackage, audience);
				log.info("audience=====>{}", JSON.toJSONString(audience));

				BeanUtils.copyProperties(audience, adPlanCreateDto);

				log.info("复制已有定向包的情况=====>{}", JSON.toJSONString(adPlanCreateDto));
				//替换的时候存在将[]变没的情况，需要重新增加[]
				//复制存在定向包时，inventoryType 已经存在[],需要去除
				if (StringUtils.isNotBlank(adPlanCreateDto.getInventoryType())){
					adPlanCreateDto.setInventoryType(Arrays.stream(JSON.parseObject(adPlanCreateDto.getInventoryType(),String[].class)).collect(Collectors.joining(",")));
				}
				adPlanCreateDto = getJsonArrString(adPlanCreateDto);

				//复制的时候，涉及到人群包权限的问题，这里直接设置为null
				adPlanCreateDto.setRetargetingTagsInclude(null);
				adPlanCreateDto.setRetargetingTagsExclude(null);
				//定向包id涉及权限的问题，这里直接设置为null
				adPlanCreateDto.setAudienceId(null);
			} else {
				//新建定向的情况，广告投放位置，监测链接需要将逗号分割的字符串-转数组
				if (StringUtils.isNotBlank(adPlanCreateDto.getInventoryType())) {
					adPlanCreateDto.setInventoryType(JSONObject.toJSONString(filterNull(adPlanCreateDto.getInventoryType().split(","))));
				}
				// 20220408 使用监测链接组不需单独传监测链接
//				if (StringUtils.isNotBlank(adPlanCreateDto.getActionTrackUrl())) {
//					adPlanCreateDto.setActionTrackUrl(JSONObject.toJSONString(filterNull(adPlanCreateDto.getActionTrackUrl().split(","))));
//				}
			}

			//增加[]
			adPlanCreateDto = dealRetargetingTags(adPlanCreateDto);

		}

		adPlanCreateDto.setHideIfConverted(Optional.ofNullable(adPlanCreateDto.getHideIfConverted()).orElse("NO_EXCLUDE"));

		//判断两个对象不为空填充
		if (null != adPlanCreateDto.getLaunchPriceFrom() && null != adPlanCreateDto.getLaunchPriceTo()) {
			Integer[] launchPrice = {adPlanCreateDto.getLaunchPriceFrom(), adPlanCreateDto.getLaunchPriceTo()};
			adPlanCreateDto.setLaunchPrice(JSONObject.toJSONString(launchPrice));
		}

		if (null != adPlanCreateDto.getRetargetingTags()) {
			adPlanCreateDto.setRetargetingTags(null);
		}
	}

	/**
	 * 查询对应广告账号对应的计划
	 *
	 * @param advertiserId
	 * @param adIds        （多个广告计划用逗号分隔）
	 * @return
	 */
	@Override
	@Async
	public void getAdPlan(String advertiserId, String adIds) {
		// 根据广告计划id 拉取广告计划数据，插入到广告计划表
		try {
			List<AdPlan> adPlanList = pullAdPlanData(advertiserId, adIds);
			if (CollectionUtils.isNotEmpty(adPlanList)) {
				//处理广告计划中audience内容存储。
				dealData(advertiserId, adPlanList);
				this.saveOrUpdateBatch(adPlanList);
			}
		} catch (Exception e) {
			logger.error("getAdvPlan is error");
			throw new BusinessException(11, "服务器异常，请稍后重试");
		}
	}

	private void dealData(String advertiserId, List<AdPlan> adPlanList) {
		for (AdPlan adPlan : adPlanList) {
			try {
				AudienceSnake audienceSnake = JsonUtil.toSnakeObject(JSON.toJSONString(adPlan.getAudience()), AudienceSnake.class);
				BeanUtils.copyProperties(audienceSnake, adPlan);
				//解析新建定向的场景
				if (audienceSnake != null) {
					String action = audienceSnake.getAction();
					if (StringUtils.isNotBlank(action)) {
						JSONObject actionObj = JSONObject.parseObject(action);
						String[] actionScene = actionObj.getObject("action_scene", String[].class);
						Integer actionDays = actionObj.getInteger("action_days");
						Integer[] actionCategories = actionObj.getObject("action_categories", Integer[].class);
						Integer[] actionWords = actionObj.getObject("action_words", Integer[].class);
						if (actionScene != null) {
							//这里应该存储与临时表保持一致，为兼容旧数据不能动了
							adPlan.setActionScene(JSON.toJSONString(actionScene));
						}
						adPlan.setActionDays(actionDays);
						if (actionCategories != null) {
							adPlan.setActionCategories(JSON.toJSONString(actionCategories));
						}
						if (actionWords != null) {
							adPlan.setActionWords(JSON.toJSONString(actionWords));
						}
					}
				}
				adPlan.setAdvertiserId(advertiserId);
			} catch (Throwable e) {
				logger.error("广告计划处理数据失败", e);
			}
		}
	}

	/**
	 * 调用头条创建广告计划(广告创意)
	 *
	 * @param paramMap
	 * @return
	 */
	@Override
	public String createThirdPlanOrCreative(Map<String, Object> paramMap, String methodName, String url, String advertiserId, Integer type) {
		String returnId = null;
		try {
			String token = ttAccesstokenService.fetchAccesstoken(advertiserId);
			if (StringUtils.isBlank(token)) {
				logger.error("createThirdPlan  is error:account or  token  is expired");
				throw new BusinessException(11, "token 失效");
			}
			logger.info(methodName + "的请求参数：" + JSON.toJSONString(paramMap));
			String resultStr = OEHttpUtils.doPost(adThirdUrl + url, paramMap, token);
			logger.info(methodName + " response:" + resultStr);
			JSONObject obj = JSON.parseObject(resultStr);
			if (null == obj) {
				log.error(methodName + " is error,调用三方响应异常");
				throw new BusinessException(11, "三方服务器异常，请稍后重试");
			}
			String code = obj.getString("code");
			if (!StringUtils.equals(code, "0")) {
				//记录日志
				logger.error(methodName + " is error:" + resultStr);
				throw new BusinessException(Integer.parseInt(code), obj.getString("message"));
			} else {
				String returnData = obj.getString("data");
				if (StringUtils.isNotBlank(returnData)) {
					if (StatusEnum.TYPE_TWO.getStatus().equals(type)) {
						//广告计划数据
						returnId = JSONObject.parseObject(returnData).get("ad_id").toString();
					} else if (StatusEnum.TYPE_THREE.getStatus().equals(type)) {
						//创建广告创意数据.当创意没有审核通过，没有返回对应的创意主键id
						return returnData;
					}
				}
			}
		} catch (Throwable e) {
			logger.error(methodName + " is error ", e);
			throw new BusinessException(11, e.getMessage());
		}
		return returnId;
	}

	public List<AdPlan> pullAdPlanData(String advertiserId, String ids) throws Exception {

		List<AdPlan> returnList = new ArrayList<>();

		if (StringUtils.isBlank(advertiserId)) {
			throw new Exception("推广账号不能为空");
		}
		String token = ttAccesstokenService.fetchAccesstoken(advertiserId);
		if (StringUtils.isBlank(token)) {
			throw new Exception("token获取为空");
		}
		int page = 1;
		while (true) {
			Map<String, Object> planParam = new HashMap<>();
			planParam.put("advertiser_id", advertiserId);
			//目前广告计划和广告创意的最大的页面大小为1000
			planParam.put("page", page);
			planParam.put("page_size", "100");
			Map<String, Object> jsonParam = new HashMap<>();
			if (StringUtils.isNotBlank(ids)) {
				long[] idArr = Arrays.stream(ids.split(",")).mapToLong(s -> Long.parseLong(s)).toArray();
				jsonParam.put("ids", idArr);
			}
			planParam.put("filtering", JSONObject.toJSON(jsonParam));
			logger.info("广告计划列表request:" + JSONObject.toJSON(planParam));
			String resultStr = OEHttpUtils.doGet(adThirdUrl + advPlanUrl, planParam, token);
			//logger.info("广告计划列表response:" + resultStr);
			ResponseBean resBean = JSON.parseObject(resultStr, ResponseBean.class);
			if (resBean != null && "0".equals(resBean.getCode())) {
				JSONObject jsonObj = resBean.getData();
				String listStr = jsonObj.getString("list");
				String page_info = jsonObj.getString("page_info");
				// String[] 类型的会转化为JSON类型的String
				List<AdPlan> list = JSONObject.parseArray(listStr, AdPlan.class);
				returnList.addAll(list);
				JSONObject jsonObject = JSONObject.parseObject(page_info);
				Long total_page = jsonObject.getLong("total_page");
				if (page >= total_page) {
					break;
				}
				page++;
			} else {
				log.info("获取广告计划异常：{},广告账户：{}", resBean.getMessage(), advertiserId);
				break;
			}

		}
		return returnList;
	}

	/**
	 * 处理字符串 用逗号分隔 转换为对应的数组字符串
	 * "111,222"  ==>  ["111","222"]
	 * 这个方法暂时不动--其实直接在调用接口时处理即可
	 *
	 * @param adPlanTempDto
	 * @return
	 */
	private AdPlanCreateDto getJsonArrString(AdPlanCreateDto adPlanTempDto) {
		Optional.ofNullable(adPlanTempDto.getAge()).filter(StringUtils::isNotEmpty).ifPresent(p -> adPlanTempDto.setAge(JSONObject.toJSONString(filterNull(p.split(",")))));
		Optional.ofNullable(adPlanTempDto.getCity()).ifPresent(p -> adPlanTempDto.setCity(JSONObject.toJSONString(filterNull(p.split(",")))));
		Optional.ofNullable(adPlanTempDto.getBusinessIds()).ifPresent(p -> adPlanTempDto.setBusinessIds(JSONObject.toJSONString(filterNull(p.split(",")))));
		Optional.ofNullable(adPlanTempDto.getActionScene()).ifPresent(p -> adPlanTempDto.setActionScene(JSONObject.toJSONString(filterNull(p.split(",")))));
		Optional.ofNullable(adPlanTempDto.getActionCategories()).ifPresent(p -> adPlanTempDto.setActionCategories(JSONObject.toJSONString(filterNull(p.split(",")))));
		Optional.ofNullable(adPlanTempDto.getActionWords()).ifPresent(p -> adPlanTempDto.setActionWords(JSONObject.toJSONString(filterNull(p.split(",")))));
		Optional.ofNullable(adPlanTempDto.getInterestCategories()).ifPresent(p -> adPlanTempDto.setInterestCategories(JSONObject.toJSONString(filterNull(p.split(",")))));
		Optional.ofNullable(adPlanTempDto.getInterestWords()).ifPresent(p -> adPlanTempDto.setInterestWords(JSONObject.toJSONString(filterNull(p.split(",")))));
		Optional.ofNullable(adPlanTempDto.getPlatform()).ifPresent(p -> adPlanTempDto.setPlatform(JSONObject.toJSONString(filterNull(p.split(",")))));
		Optional.ofNullable(adPlanTempDto.getAc()).filter(StringUtils::isNotEmpty).ifPresent(p -> adPlanTempDto.setAc(JSONObject.toJSONString(filterNull(p.split(",")))));
		Optional.ofNullable(adPlanTempDto.getDeviceBrand()).ifPresent(p -> adPlanTempDto.setDeviceBrand(JSONObject.toJSONString(filterNull(p.split(",")))));
		Optional.ofNullable(adPlanTempDto.getInventoryType()).ifPresent(p -> adPlanTempDto.setInventoryType(JSONObject.toJSONString(filterNull(p.split(",")))));
		Optional.ofNullable(adPlanTempDto.getActionTrackUrl()).ifPresent(p -> adPlanTempDto.setActionTrackUrl(JSONObject.toJSONString(filterNull(p.split(",")))));
		Optional.ofNullable(adPlanTempDto.getStartTime()).ifPresent(p -> adPlanTempDto.setStartTime(DateUtil.getDateFormat("yyyy-MM-dd HH:mm").format(DateUtil.stringToDate(p, "yyyy-MM-dd HH:mm"))));
		Optional.ofNullable(adPlanTempDto.getEndTime()).ifPresent(p -> adPlanTempDto.setEndTime(DateUtil.getDateFormat("yyyy-MM-dd HH:mm").format(DateUtil.stringToDate(p, "yyyy-MM-dd HH:mm"))));
		return adPlanTempDto;
	}

	private String[] filterNull(String[] array) {
		return Arrays.stream(array).filter(v -> StringUtils.isNotBlank(v)).toArray(String[]::new);
	}

	@SneakyThrows
	public static void main(String[] args) {
		AdPlanCreateDto adPlanTempDto = new AdPlanCreateDto();
		adPlanTempDto.setRetargetingTagsExclude("");
		adPlanTempDto.setRetargetingTagsInclude("");
		if (StringUtils.isBlank(adPlanTempDto.getRetargetingTagsInclude())) {
			adPlanTempDto.setRetargetingTagsInclude(null);
		}
		if (StringUtils.isBlank(adPlanTempDto.getRetargetingTagsExclude())) {
			adPlanTempDto.setRetargetingTagsExclude(null);
		}
		Optional.ofNullable(adPlanTempDto.getRetargetingTagsInclude()).ifPresent(p -> adPlanTempDto.setRetargetingTagsInclude(JSONObject.toJSONString(p.split(","))));
		Optional.ofNullable(adPlanTempDto.getRetargetingTagsExclude()).ifPresent(p -> adPlanTempDto.setRetargetingTagsExclude(JSONObject.toJSONString(p.split(","))));
		String paramJson = JsonUtil.toUnderlineJSONString(adPlanTempDto);
		log.info("paramJson=====>{}", paramJson);
		Map<String, Object> paramMap = JsonUtil.parseJSON2Map(paramJson);
		log.info("paramMap=====>{}", JSON.toJSONString(paramMap));
//		adPlanTempDto.setActionCategories("[2,4,6,11,16,20]");
//		//Optional.ofNullable(adPlanTempDto.getActionCategories()).ifPresent(p -> adPlanTempDto.setActionCategories(JSONObject.toJSONString(p.split(","))));
//		String actionCategories = adPlanTempDto.getActionCategories();
//		System.out.println(actionCategories);
//		//actionCategories = ["123","124"]
//		List<String> tmpArray = (List) JSONArray.parse(actionCategories);
//		int[] aa= tmpArray.stream().filter(v -> StringUtils.isNotBlank(v)).mapToInt(Integer::valueOf).toArray();
//		System.out.println(adPlanTempDto.getActionCategories());
//		String actionScene = "[\"APP\",\"APP1\"]";
//		String a = "[16,20,6,11,4,2]";
//
//		String aa = "[]";
//		Integer[] aaa= JSON.parseObject(aa,Integer[].class);
//		JSONArray actionSceneArray = JSON.parseArray(aa);
//
//		Object[] value = actionSceneArray.toArray();
		System.out.println(adPlanTempDto.getRetargetingTagsInclude());

		String url = "https://apps.bytesfield.com/download/extend/cur/81569d88089d74a539df39eab0bc05acb07421ad/54x219x96x828";
		String[] strs = url.split("/");
		System.out.println(strs.length);

		System.out.println("123".concat("x").concat("789"));

	}

	/**
	 * 处理定向包的定向和排除
	 * "111,222"  ==>  ["111","222"]
	 *
	 * @param adPlanTempDto
	 * @return
	 */
	public static AdPlanCreateDto dealRetargetingTags(AdPlanCreateDto adPlanTempDto) {
		if (StringUtils.isBlank(adPlanTempDto.getRetargetingTagsInclude())) {
			adPlanTempDto.setRetargetingTagsInclude(null);
		}
		if (StringUtils.isBlank(adPlanTempDto.getRetargetingTagsExclude())) {
			adPlanTempDto.setRetargetingTagsExclude(null);
		}
		Optional.ofNullable(adPlanTempDto.getRetargetingTagsInclude()).ifPresent(p -> adPlanTempDto.setRetargetingTagsInclude(JSONObject.toJSONString(p.split(","))));
		Optional.ofNullable(adPlanTempDto.getRetargetingTagsExclude()).ifPresent(p -> adPlanTempDto.setRetargetingTagsExclude(JSONObject.toJSONString(p.split(","))));
		return adPlanTempDto;
	}

	/**
	 * 按广告组、广告计划名称查询
	 *
	 * @param adPlanDto
	 * @return
	 */
	@Override
	public List<AdPlan> getByName(AdPlanDto adPlanDto) {
		return baseMapper.selectAdPlanList(adPlanDto);
	}

	@Override
	public List<AdPlan> getByAdvertiserIds(AdPlanTempDto adPlanTempDto) {
		AdPlanDto adPlanDto = new AdPlanDto();
		String advertiserIds = adPlanTempDto.getAdvertiserIds();
		String status = adPlanTempDto.getStatus();
		String adName = adPlanTempDto.getAdName();
		adPlanDto.setAdPlanLimit(sdkProperties.getAdPlanLimit());
		if (StringUtils.isNotBlank(status)) {
			adPlanDto.setStatus(status);
		}
		if (StringUtils.isNotEmpty(adName)){
			adPlanDto.setAdName(adName);
		}
		if (StringUtils.isNotBlank(advertiserIds)) {
			adPlanDto.setAdvertiserId(advertiserIds);
		} else {
			return Lists.newArrayList();
		}
		if (PlatformTypeEnum.TT.getValue().equals(adPlanTempDto.getMediaCode())) {
			return baseMapper.selectAdPlanListByadvertiserIds(adPlanDto);
		} else if (PlatformTypeEnum.GDT.getValue().equals(adPlanTempDto.getMediaCode())) {
			String[] idrr = advertiserIds.split(",");
			if (idrr.length > 0) {
				QueryWrapper<GdtAdgroup> queryWrapper = new QueryWrapper<GdtAdgroup>().in("account_id", Arrays.asList(idrr));
				if (StringUtils.isNotEmpty(adName)){
					queryWrapper.and(qr -> qr.like("adgroup_id",adName).or().like("adgroup_name",adName));
				}
				queryWrapper.last("limit "+sdkProperties.getAdPlanLimit());
				List<GdtAdgroup> gdtAdgroupList = gdtAdgroupMapper.selectList(queryWrapper);
				if (CollectionUtils.isNotEmpty(gdtAdgroupList)) {
					return gdtAdgroupList.stream().map(gdtAdgroup -> {
						AdPlan adPlan = new AdPlan();
						adPlan.setAdId(gdtAdgroup.getAdgroupId());
						adPlan.setAdName(gdtAdgroup.getAdgroupName());
						return adPlan;
					}).collect(Collectors.toList());
				}
			}
		} else if (PlatformTypeEnum.KS.getValue().equals(adPlanTempDto.getMediaCode())) {
			String[] idrr = advertiserIds.split(",");
			if (idrr.length > 0) {
				QueryWrapper<KsUnit> ksUnitQueryWrapper = new QueryWrapper<KsUnit>().in("advertiser_id", Arrays.asList(idrr));
				if (StringUtils.isNotEmpty(adName)){
					ksUnitQueryWrapper.and(qr -> qr.like("unit_id",adName).or().like("unit_name",adName));
				}
				ksUnitQueryWrapper.eq("deleted", 0);
				ksUnitQueryWrapper.orderByDesc("update_time").last("limit "+sdkProperties.getAdPlanLimit());
				ksUnitQueryWrapper.eq("deleted", 0);
				List<KsUnit> ksUnitList = ksUnitMapper.selectList(ksUnitQueryWrapper);
				if (CollectionUtils.isNotEmpty(ksUnitList)) {
					return ksUnitList.stream().map(ksUnit -> {
						AdPlan adPlan = new AdPlan();
						adPlan.setAdId(ksUnit.getUnitId());
						adPlan.setAdName(ksUnit.getUnitName());
						return adPlan;
					}).collect(Collectors.toList());
				}
			}
		} else if (PlatformTypeEnum.BD.getValue().equals(adPlanTempDto.getMediaCode())) {
			String[] idrr = advertiserIds.split(",");
			if (idrr.length > 0) {
				List<BdAdgroup> adgroupList = bdAdgroupService.list(Wrappers.<BdAdgroup>lambdaQuery()
						.in(BdAdgroup::getAdvertiserId, Arrays.asList(idrr))
						.in(BdAdgroup::getDeleted, 0).orderByDesc(BdAdgroup::getUpdateTime));
				if (CollectionUtils.isNotEmpty(adgroupList)) {
					return adgroupList.stream().map(adgroup -> {
						AdPlan adPlan = new AdPlan();
						adPlan.setAdId(adgroup.getAdgroupFeedId());
						adPlan.setAdName(adgroup.getAdgroupFeedName());
						return adPlan;
					}).collect(Collectors.toList());
				}
			}
		}
		return Lists.newArrayList();
	}

	/**
	 * 修改广告计划预算
	 *
	 * @param budgetDto
	 * @return
	 */
	@Override
	public R updatePlanBudget(BudgetDto budgetDto) {
		return advCampaignService.budgetUpdate(budgetDto, StatusEnum.OPERATE_THREE.getStatus());
	}

	/**
	 * 修改广告计划出价
	 *
	 * @param budgetDto
	 * @return
	 */
	@Override
	public R updatePlanCpaBid(BudgetDto budgetDto) {
		/*pricing为"OCPC"时取值范围：0.1-10000元；pricing为"OCPM"时取值范围：0.1-10000元；出价不能大于预算否则会报错*/
		if(budgetDto.getVersionType().equals("2")){
			AdPromotion adPromotion = adPromotionMapper.selectByPromotionId(budgetDto.getAdId());
			if (null == adPromotion) {
				return R.failed("当前广告计划不存在");
			}
			if (null != budgetDto.getCpaBid()) {
				Boolean flag = budgetDto.getCpaBid().compareTo(new BigDecimal("0.1")) == -1 || budgetDto.getCpaBid().compareTo(new BigDecimal(10000)) == 1;
				if (flag) {
					return R.failed("pricing为OCPC或OCPC时取值范围：0.1-10000元.并且不能大于预算");
				}
			}
		}else {
			AdPlan adPlan = baseMapper.selectById(budgetDto.getAdId());
			if (null == adPlan) {
				return R.failed("当前广告计划不存在");
			}
			if (null != budgetDto.getCpaBid()) {
				Boolean flag = budgetDto.getCpaBid().compareTo(new BigDecimal("0.1")) == -1 || budgetDto.getCpaBid().compareTo(new BigDecimal(10000)) == 1 || budgetDto.getCpaBid().compareTo(adPlan.getBudget()) == 1;
				if (flag) {
					return R.failed("pricing为OCPC或OCPC时取值范围：0.1-10000元.并且不能大于预算");
				}
			}
		}
		R r = advCampaignService.updateThirdData(new AdvertiserDto(Long.parseLong(budgetDto.getAdvertiserId()), budgetDto.getAdId(), budgetDto.getCpaBid(),budgetDto.getVersionType()), StatusEnum.TYPE_FOUR.getStatus());
		if (r.getCode() == 0) {
			if(budgetDto.getVersionType().equals("2")){
				adPromotionMapper.updateByPrimaryKeySelective(new AdPromotion(budgetDto.getAdId(), null, budgetDto.getCpaBid()));
			}else {
				baseMapper.updateById(new AdPlan(budgetDto.getAdId(), null, budgetDto.getCpaBid()));
			}
			return R.ok();
		} else {
			return r;
		}

	}

	@Override
	public List<AdPlan> getByAdids(String adids) {
		List<AdPlan> adPlans = baseMapper.selectAdPlanListByAdids(adids);
		converAdPlans(adPlans);
		return adPlans;
	}

	@Override
	public List<PlanGdtAttrAnalyseReportVo> getGdtByAdids(String adids) {
		List<GdtAdgroup> adPlans = gdtAdgroupMapper.selectGdtAdgroupListByAdids(adids);
		return converGdtAdgroups(adPlans);
	}

	private List<PlanGdtAttrAnalyseReportVo> converGdtAdgroups(List<GdtAdgroup> gdtAdgroups) {
		List<PlanGdtAttrAnalyseReportVo> vos = Lists.newArrayList();
		if (CollectionUtils.isEmpty(gdtAdgroups)) {
			return vos;
		}
		Map<String, String> allGdtPackThirdIdNames = getAllGdtPackThirdIdNames();
		Map<String, String> allGdtActioninterestNames = getAllGdtActioninterestNames();
		//字典转化
		gdtAdgroups.stream().forEach(v -> {
			PlanGdtAttrAnalyseReportVo vo = new PlanGdtAttrAnalyseReportVo();
			vo.setId(String.valueOf(v.getAdgroupId()));
			vo.setName(v.getAdgroupName());
			vo.setAdStatus(GdtAdStatusEnum.valueByType(v.getStatus()));
			if (StringUtils.isBlank(v.getEndDate())) {
				vo.setThrowDays((int) converDay(v.getBeginDate(), DateUtils.dateToString(new Date(), DateUtils.YYYY_MM_DD), DateUtils.YYYY_MM_DD));
			} else {
				vo.setThrowDays((int) converDay(v.getBeginDate(), v.getEndDate(), DateUtils.YYYY_MM_DD));
			}
			String targeting = v.getTargeting();
			if (StringUtils.isNotBlank(targeting) && targeting.startsWith(Constants.PRE_BIG_BRACKETS)) {
				JSONObject jsonObject = JSONObject.parseObject(targeting);
				vo.setAge(converGtdAge(jsonObject));
				vo.setGender(converGtdGender(jsonObject));
				vo.setGameUserConsumeAbility(converGameUserConsumeAbility(jsonObject));
				vo.setDefRetargetingUser(converDefRetargetingUser(jsonObject, allGdtPackThirdIdNames));
				vo.setRetargetingTagsExclude(converRetargetingTagsExclude(jsonObject, allGdtPackThirdIdNames));
				JSONObject boi = (JSONObject) jsonObject.get(ToutiaoGdtAudiencePackageFieldsEnum.behavior_or_interest.getType());
				if (!Objects.isNull(boi)) {
					vo.setAction(converAction(boi, allGdtActioninterestNames));
					vo.setInterest(converInterest(boi, allGdtActioninterestNames));
					vo.setIntention(converIntention(boi, allGdtActioninterestNames));
				}
			}
			vo.setAutoExpand(convertExpandTargeting(v.getExpandTargeting()));
			vo.setAutoExpandEnable(GdtAutoExpanEnableEnum.valueByType(v.getExpandEnabled()));
			vo.setOptimizeTarget(GdtOptimizationGoalEnum.valueByType(v.getOptimizationGoal()));
			vo.setBidStrategy(GdtBidStrategyEnum.valueByType(v.getBidStrategy()));
			vo.setBid(v.getBidAmount());
			String deepConversionSpec = v.getDeepConversionSpec();
			JSONObject jsonObject = null;
			if (StringUtils.isNotBlank(deepConversionSpec) && deepConversionSpec.startsWith(Constants.PRE_BIG_BRACKETS) &&
					!Objects.isNull(jsonObject = JSONObject.parseObject(deepConversionSpec))
					&& !Objects.isNull(jsonObject = jsonObject.getJSONObject(ToutiaoGdtAudiencePackageFieldsEnum.deep_conversion_behavior_spec.getType()))
			) {
				vo.setDeepOptimizeTarget(GdtOptimizationGoalEnum.valueByType(String.valueOf(jsonObject.get(ToutiaoGdtAudiencePackageFieldsEnum.goal.getType()))));
				vo.setDeepTargetBid(String.valueOf(jsonObject.get(ToutiaoGdtAudiencePackageFieldsEnum.bid_amount.getType())));
			}
			vo.setAdThrowLoaction(converAdThrowLoaction(v.getSiteSet()));
			vos.add(vo);
		});
		return vos;
	}

	private long converDay(String startTime, String endTime, String dateFormat) {
		try {
			long hour = cn.hutool.core.date.DateUtil.between(cn.hutool.core.date.DateUtil.parse(startTime, dateFormat), cn.hutool.core.date.DateUtil.parse(endTime, dateFormat), DateUnit.HOUR, false);
			long day = hour % 24 > 0 ? 1 : 0;
			if (hour <= 24) {
				return day;
			} else {
				return cn.hutool.core.date.DateUtil.between(cn.hutool.core.date.DateUtil.parse(startTime, dateFormat), cn.hutool.core.date.DateUtil.parse(endTime, dateFormat), DateUnit.DAY, false) + day;
			}
		} catch (Exception e) {
			return 0L;
		}
	}

	private String convertExpandTargeting(String expandTargeting) {
		try {
			String[] expandT = JSON.parseObject(expandTargeting, String[].class);
			if (ArrayUtil.isNotEmpty(expandT)) {
				return ArrayUtil.join(Arrays.stream(expandT).toArray(), Constants.COMMA);
			} else {
				return Constants.EMPTTYSTR;
			}
		} catch (Exception e) {
			return Constants.EMPTTYSTR;
		}
	}

	private String converAdThrowLoaction(String json) {
		try {
			String[] genderArr = JSON.parseObject(json, String[].class);
			if (ArrayUtil.isNotEmpty(genderArr)) {
				return ArrayUtil.join(Arrays.stream(genderArr).map(v -> gdtAdgroupTempService.getSiteSetValue(v)).toArray(), Constants.COMMA);
			} else {
				return Constants.EMPTTYSTR;
			}
		} catch (Exception e) {
			return Constants.EMPTTYSTR;
		}
	}

	private String converInterest(JSONObject jsonObject, Map<String, String> allGdtActioninterestNames) {
		try {
			Object arr = jsonObject.getJSONObject(ToutiaoGdtAudiencePackageFieldsEnum.interest.getType());
			if (!Objects.isNull(arr) && ArrayUtil.isNotEmpty(arr = ((JSONObject) arr).get(ToutiaoGdtAudiencePackageFieldsEnum.category_id_list.getType()))) {
				if (MapUtils.isEmpty(allGdtActioninterestNames)) {
					return ArrayUtil.join(((JSONArray) arr).stream().toArray(), Constants.COMMA);
				} else {
					return ArrayUtil.join(((JSONArray) arr).stream().map(v -> allGdtActioninterestNames.get(String.format("%s:%s", v, GdtLabelTypeEnum.INTEREST.getType())))
							.filter(v -> StringUtils.isNotBlank(v)).toArray(), Constants.COMMA);
				}
			} else {
				return Constants.EMPTTYSTR;
			}
		} catch (Exception e) {
			return Constants.EMPTTYSTR;
		}
	}

	private String converIntention(JSONObject jsonObject, Map<String, String> allGdtActioninterestNames) {
		try {
			Object arr = jsonObject.getJSONObject(ToutiaoGdtAudiencePackageFieldsEnum.intention.getType());
			if (!Objects.isNull(arr) && ArrayUtil.isNotEmpty(arr = ((JSONObject) arr).get(ToutiaoGdtAudiencePackageFieldsEnum.targeting_tags.getType()))) {
				if (MapUtils.isEmpty(allGdtActioninterestNames)) {
					return ArrayUtil.join(((JSONArray) arr).stream().toArray(), Constants.COMMA);
				} else {
					return ArrayUtil.join(((JSONArray) arr).stream().map(v -> allGdtActioninterestNames.get(String.format("%s:%s", v, GdtLabelTypeEnum.INTENTION.getType())))
							.filter(v -> StringUtils.isNotBlank(v)).toArray(), Constants.COMMA);
				}
			} else {
				return Constants.EMPTTYSTR;
			}
		} catch (Exception e) {
			return Constants.EMPTTYSTR;
		}
	}

	private String converAction(JSONObject jsonObject, Map<String, String> allGdtActioninterestNames) {
		try {
			JSONArray arr = jsonObject.getJSONArray(ToutiaoGdtAudiencePackageFieldsEnum.behavior.getType());
			if (ArrayUtil.isNotEmpty(arr)) {
				List reList = Lists.newArrayList();
				arr.stream().forEach(v -> {
					JSONArray ja = ((JSONObject) v).getJSONArray(ToutiaoGdtAudiencePackageFieldsEnum.category_id_list.getType());
					if (ArrayUtil.isNotEmpty(ja)) {
						reList.addAll(ja.stream().collect(Collectors.toList()));
					}
				});
				if (CollectionUtils.isNotEmpty(reList) && !MapUtils.isEmpty(allGdtActioninterestNames)) {
					return ArrayUtil.join(reList.stream().map(v -> allGdtActioninterestNames.get(String.format("%s:%s", v, GdtLabelTypeEnum.BEHAVIOR.getType())))
							.filter(v -> !Objects.isNull(v)).toArray(), Constants.COMMA);
				} else if (CollectionUtils.isNotEmpty(reList)) {
					return ArrayUtil.join(reList.stream().toArray(), Constants.COMMA);
				}
			}
			return Constants.EMPTTYSTR;
		} catch (Exception e) {
			return Constants.EMPTTYSTR;
		}
	}

	private String converRetargetingTagsExclude(JSONObject jsonObject, Map<String, String> allTtPackThirdIdNames) {
		try {
			JSONArray custom = jsonObject.getJSONArray(ToutiaoGdtAudiencePackageFieldsEnum.excluded_custom_audience.getType());
			if (ArrayUtil.isEmpty(custom)) {
				return Constants.EMPTTYSTR;
			}
			if (!MapUtils.isEmpty(allTtPackThirdIdNames)) {
				// 通过人群ID获取人群信息
				return ArrayUtil.join(custom.stream().map(v -> allTtPackThirdIdNames.get(String.valueOf(v))).filter(v -> StringUtils.isNotBlank(v)).toArray(), Constants.COMMA);
			} else {
				return ArrayUtil.join(custom.stream().toArray(), Constants.COMMA);
			}
		} catch (Exception e) {
			return Constants.EMPTTYSTR;
		}
	}

	private String converDefRetargetingUser(JSONObject jsonObject, Map<String, String> allTtPackThirdIdNames) {
		try {
			JSONArray custom = jsonObject.getJSONArray(ToutiaoGdtAudiencePackageFieldsEnum.custom_audience.getType());
			if (ArrayUtil.isEmpty(custom)) {
				return Constants.EMPTTYSTR;
			}
			if (!MapUtils.isEmpty(allTtPackThirdIdNames)) {
				//通过人群ID获取人群信息
				return ArrayUtil.join(custom.stream().map(v -> allTtPackThirdIdNames.get(String.valueOf(v))).filter(v -> StringUtils.isNotBlank(v)).toArray(), Constants.COMMA);
			} else {
				return ArrayUtil.join(custom.stream().toArray(), Constants.COMMA);
			}
		} catch (Exception e) {
			return Constants.EMPTTYSTR;
		}
	}

	private String converGameUserConsumeAbility(JSONObject jsonObject) {
		try {
			JSONArray genderArr = jsonObject.getJSONArray(ToutiaoGdtAudiencePackageFieldsEnum.game_consumption_level.getType());
			if (ArrayUtil.isNotEmpty(genderArr)) {
				return ArrayUtil.join(genderArr.stream().map(v -> GdtGameConsumptionLevelEnum.valueByType(String.valueOf(v))).toArray(), Constants.COMMA);
			} else {
				return Constants.EMPTTYSTR;
			}
		} catch (Exception e) {
			return Constants.EMPTTYSTR;
		}
	}

	private String converGtdAge(JSONObject jsonObject) {
		try {
			JSONArray ageArr = jsonObject.getJSONArray(ToutiaoGdtAudiencePackageFieldsEnum.age.getType());
			if (ArrayUtil.isNotEmpty(ageArr)) {
				return ArrayUtil.join(ageArr.stream().map(v -> String.format("%s_%s", ((JSONObject) v).get(ToutiaoGdtAudiencePackageFieldsEnum.min.getType()),
						((JSONObject) v).get(ToutiaoGdtAudiencePackageFieldsEnum.max.getType()))).toArray(), Constants.COMMA);
			} else {
				return Constants.EMPTTYSTR;
			}
		} catch (Exception e) {
			return Constants.EMPTTYSTR;
		}
	}

	private String converGtdGender(JSONObject jsonObject) {
		try {
			JSONArray genderArr = jsonObject.getJSONArray(ToutiaoGdtAudiencePackageFieldsEnum.gender.getType());
			if (ArrayUtil.isNotEmpty(genderArr)) {
				return ArrayUtil.join(genderArr.stream().map(v -> GdtGenderEnum.valueByType(String.valueOf(v))).toArray(), Constants.COMMA);
			} else {
				return Constants.EMPTTYSTR;
			}
		} catch (Exception e) {
			return Constants.EMPTTYSTR;
		}
	}

	private void converAdPlans(List<AdPlan> adPlans) {
		if (CollectionUtils.isEmpty(adPlans)) {
			return;
		}
		Map<String, String> allTtPackThirdIdNames = getAllTtPackThirdIdNames();
		Map<String, String> allTtActioninterestNames = getAllTtActioninterestNames();
		//填充素材
		fillTtMaterialVo(adPlans);
		//字典转化
		adPlans.stream().forEach(v -> {
			v.setGender(ToutiaoGenderEnum.valueByType(v.getGender()));
			v.setAge(converAge(v.getAge()));
			v.setRetargetingTagsExclude(converTtRetargetingTags(v.getRetargetingTagsExclude(), allTtPackThirdIdNames));
			v.setRetargetingTagsInclude(converTtRetargetingTags(v.getRetargetingTagsInclude(), allTtPackThirdIdNames));
			v.setRoiGoal(v.getRoiGoal());
			v.setActionScene(converActionScene(v.getActionScene()));
			v.setActionWords(converTtActionWords(v.getActionWords(), allTtActioninterestNames));
			v.setInterestCategories(converTtInterestCategories(v.getActionWords(), allTtActioninterestNames));
			v.setInterestWords(converTtInterestWords(v.getActionWords(), allTtActioninterestNames));
			v.setBudgetMode(ToutiaoBudgetTypeEnum.valueByType(v.getBudgetMode()));
			v.setStatus(ToutiaoAdStatusEnum.valueByType(v.getStatus()));
			v.setInventoryType((converTtInventoryType(v.getInventoryType())));
		});
	}

	private Map<String, String> getAllTtPackThirdIdNames() {
		String value = stringRedisTemplate.opsForValue().get(TT_PACK_THIRDID_NAME_KEY);
		if (StringUtils.isNotBlank(value) && TT_PACK_THIRDID_NAME_KEY_LOADED) {
			return JSON.parseObject(value, Map.class);
		}
		Map<String, String> values = Maps.newHashMap();
		synchronized (TT_PACK_THIRDID_NAME_KEY) {
			value = stringRedisTemplate.opsForValue().get(TT_PACK_THIRDID_NAME_KEY);
			if (StringUtils.isNotBlank(value) && TT_PACK_THIRDID_NAME_KEY_LOADED) {
				return JSON.parseObject(value, Map.class);
			}
			List<TtCustomAudience> allThirdIdAndName = ttCustomAudienceService.getAllThirdIdAndNames();
			TT_PACK_THIRDID_NAME_KEY_LOADED = true;
			if (CollectionUtils.isEmpty(allThirdIdAndName)) {
				stringRedisTemplate.opsForValue().set(TT_PACK_THIRDID_NAME_KEY, Constants.BIG_BRACKETS, dictCacheTime, TimeUnit.MINUTES);
				return values;
			} else {
				allThirdIdAndName.forEach(v -> {
					values.put(String.valueOf(v.getCustomAudienceId()), v.getName());
				});
				stringRedisTemplate.opsForValue().set(TT_PACK_THIRDID_NAME_KEY, JSON.toJSONString(values), dictCacheTime, TimeUnit.MINUTES);
				return values;
			}
		}
	}

	private Map<String, String> getAllGdtPackThirdIdNames() {
		String value = stringRedisTemplate.opsForValue().get(GDT_PACK_THIRDID_NAME_KEY);
		if (StringUtils.isNotBlank(value) && GDT_PACK_THIRDID_NAME_KEY_LOADED) {
			return JSON.parseObject(value, Map.class);
		}
		Map<String, String> values = Maps.newHashMap();
		synchronized (GDT_PACK_THIRDID_NAME_KEY) {
			value = stringRedisTemplate.opsForValue().get(GDT_PACK_THIRDID_NAME_KEY);
			if (StringUtils.isNotBlank(value) && GDT_PACK_THIRDID_NAME_KEY_LOADED) {
				return JSON.parseObject(value, Map.class);
			}
			List<GdtCustomAudiences> allThirdIdAndName = gdtCustomAudiencesService.getAllThirdIdAndNames();
			GDT_PACK_THIRDID_NAME_KEY_LOADED = true;
			if (CollectionUtils.isEmpty(allThirdIdAndName)) {
				stringRedisTemplate.opsForValue().set(GDT_PACK_THIRDID_NAME_KEY, Constants.BIG_BRACKETS, dictCacheTime, TimeUnit.MINUTES);
				return values;
			} else {
				allThirdIdAndName.forEach(v -> {
					values.put(String.valueOf(v.getAudienceId()), v.getName());
				});
				stringRedisTemplate.opsForValue().set(GDT_PACK_THIRDID_NAME_KEY, JSON.toJSONString(values), dictCacheTime, TimeUnit.MINUTES);
				return values;
			}
		}
	}

	private Map<String, String> getAllGdtActioninterestNames() {
		String value = stringRedisTemplate.opsForValue().get(GDT_ACTION_INTEREST_THIRDID_NAME_KEY);
		if (StringUtils.isNotBlank(value) && GDT_ACTION_INTEREST_THIRDID_NAME_KEY_LOADED) {
			return JSON.parseObject(value, Map.class);
		}
		Map<String, String> values = Maps.newHashMap();
		synchronized (GDT_ACTION_INTEREST_THIRDID_NAME_KEY) {
			value = stringRedisTemplate.opsForValue().get(GDT_ACTION_INTEREST_THIRDID_NAME_KEY);
			if (StringUtils.isNotBlank(value) && GDT_ACTION_INTEREST_THIRDID_NAME_KEY_LOADED) {
				return JSON.parseObject(value, Map.class);
			}
			List<GdtActionInterest> allThirdIdAndName = gdtActionInterestService.getAllThirdIdAndNames();
			GDT_ACTION_INTEREST_THIRDID_NAME_KEY_LOADED = true;
			if (CollectionUtils.isEmpty(allThirdIdAndName)) {
				stringRedisTemplate.opsForValue().set(GDT_ACTION_INTEREST_THIRDID_NAME_KEY, Constants.BIG_BRACKETS, dictCacheTime, TimeUnit.MINUTES);
				return values;
			} else {
				allThirdIdAndName.forEach(v -> {
					values.put(String.valueOf(String.format("%s:%s", v.getThirdId(), v.getType())), v.getThirdName());
				});
				stringRedisTemplate.opsForValue().set(GDT_ACTION_INTEREST_THIRDID_NAME_KEY, JSON.toJSONString(values), dictCacheTime, TimeUnit.MINUTES);
				return values;
			}
		}
	}

	private Map<String, String> getAllTtActioninterestNames() {
		String value = stringRedisTemplate.opsForValue().get(TT_ACTION_INTEREST_THIRDID_NAME_KEY);
		if (StringUtils.isNotBlank(value) && TT_ACTION_INTEREST_THIRDID_NAME_KEY_LOADED) {
			return JSON.parseObject(value, Map.class);
		}
		Map<String, String> values = Maps.newHashMap();
		synchronized (TT_ACTION_INTEREST_THIRDID_NAME_KEY) {
			value = stringRedisTemplate.opsForValue().get(TT_ACTION_INTEREST_THIRDID_NAME_KEY);
			if (StringUtils.isNotBlank(value) && TT_ACTION_INTEREST_THIRDID_NAME_KEY_LOADED) {
				return JSON.parseObject(value, Map.class);
			}
			List<AdActionInterest> allThirdIdAndName = adActionInterestService.getAllThirdIdAndNames();
			TT_ACTION_INTEREST_THIRDID_NAME_KEY_LOADED = true;
			if (CollectionUtils.isEmpty(allThirdIdAndName)) {
				stringRedisTemplate.opsForValue().set(TT_ACTION_INTEREST_THIRDID_NAME_KEY, JSON.toJSONString(values), dictCacheTime, TimeUnit.MINUTES);
				return values;
			} else {
				allThirdIdAndName.forEach(v -> {
					values.put(String.valueOf(String.format("%s:%s", v.getThirdId(), v.getType())), v.getName());
				});
				stringRedisTemplate.opsForValue().set(TT_ACTION_INTEREST_THIRDID_NAME_KEY, JSON.toJSONString(values), dictCacheTime, TimeUnit.MINUTES);
				return values;
			}
		}
	}

	private String converTtInventoryType(String inventoryType) {
		try {
			if (StringUtils.isNotBlank(inventoryType) && inventoryType.startsWith(Constants.PRE_MIDDLE_BRACKETS) && inventoryType.endsWith(Constants.SUFFIX_MIDDLE_BRACKETS)) {
				String[] vs = JSON.parseObject(inventoryType, String[].class);
				String val = ArrayUtil.join(Arrays.stream(vs).map(v -> advCampaignServiceImpl.transValue(v)).toArray(), Constants.COMMA);
				if (StringUtils.isNotBlank(val)) {
					return val;
				}
			}
			return Constants.EMPTTYSTR;
		} catch (Exception e) {
			return Constants.EMPTTYSTR;
		}
	}

	private void fillTtMaterialVo(List<AdPlan> adPlans) {
		Set<String> materialIds = Sets.newHashSet();
		adPlans.forEach(v -> {
			List<AdCreative> adCreatives;
			if (CollectionUtils.isNotEmpty(adCreatives = v.getAdCreatives())) {
				adCreatives.forEach(v1 -> {
					if (StringUtils.isNotBlank(v1.getImageIds()) && v1.getImageIds().startsWith(Constants.PRE_MIDDLE_BRACKETS)
							&& v1.getImageIds().endsWith(Constants.SUFFIX_MIDDLE_BRACKETS)) {
						materialIds.addAll(JSON.parseArray(v1.getImageIds(), String.class));
					}
					if (StringUtils.isNotBlank(v1.getVideoId())) {
						materialIds.add(v1.getVideoId());
					}
				});
			}
		});
		Map<String, MaterialVo> materialVoMap = Maps.newHashMap();
		if (CollectionUtils.isNotEmpty(materialIds)) {
			List<MaterialVo> materialVos = this.baseMapper.selectMaterialVosByMaterialIds(materialIds);
			if (CollectionUtils.isNotEmpty(materialVos)) {
				materialVos.forEach(v -> materialVoMap.put(v.getMId(), v));
			}
		}
		if (MapUtils.isEmpty(materialVoMap)) {
			return;
		}
		adPlans.forEach(v -> {
			List<AdCreative> adCreatives;
			if (CollectionUtils.isNotEmpty(adCreatives = v.getAdCreatives())) {
				adCreatives.forEach(v1 -> {
					if (StringUtils.isNotBlank(v1.getImageIds()) && v1.getImageIds().startsWith(Constants.PRE_MIDDLE_BRACKETS)
							&& v1.getImageIds().endsWith(Constants.SUFFIX_MIDDLE_BRACKETS)) {
						JSON.parseArray(v1.getImageIds(), String.class).forEach(v2 -> {
							if (!Objects.isNull(materialVoMap.get(v2))) {
								v.getMaterialVos().add(materialVoMap.get(v2));
							}
						});
					}
					if (StringUtils.isNotBlank(v1.getVideoId()) && !Objects.isNull(materialVoMap.get(v1.getVideoId()))) {
						v.getMaterialVos().add(materialVoMap.get(v1.getVideoId()));
					}
				});
			}
		});
	}

	private void fillTdtMaterialVo(List<GdtAdgroup> adPlans) {
	}

	private String converTtInterestWords(String interestWords, Map<String, String> allTtActioninterestNames) {
		try {
			String[] ageArr = JSON.parseObject(interestWords, String[].class);
			// 兴趣关键词   找到分类字典信息
			if (ArrayUtil.isNotEmpty(ageArr)) {
				return ArrayUtil.join(Arrays.stream(ageArr).map(v -> allTtActioninterestNames.get(String.format("%s:%s",
						v, ToutiaoActionInterestEnum.INTERESTWORDS.getType()))).filter(v -> StringUtils.isNotBlank(v)).toArray(), Constants.COMMA);
			} else {
				return Constants.EMPTTYSTR;
			}
		} catch (Exception e) {
			return Constants.EMPTTYSTR;
		}
	}

	private String converTtInterestCategories(String interestCategories, Map<String, String> allTtActioninterestNames) {
		try {
			String[] ageArr = JSON.parseObject(interestCategories, String[].class);
			//兴趣分类   找到分类字典信息
			if (ArrayUtil.isNotEmpty(ageArr)) {
				return ArrayUtil.join(Arrays.stream(ageArr).map(v -> allTtActioninterestNames.get(String.format("%s:%s", v, ToutiaoActionInterestEnum.INTERESTCATEGORIES.getType())))
						.filter(v -> StringUtils.isNotBlank(v)).toArray(), Constants.COMMA);
			} else {
				return Constants.EMPTTYSTR;
			}
		} catch (Exception e) {
			return Constants.EMPTTYSTR;
		}
	}

	private String converTtActionWords(String actionWords, Map<String, String> allTtActioninterestNames) {
		try {
			String[] ageArr = JSON.parseObject(actionWords, String[].class);
			//行为关键词
			if (ArrayUtil.isNotEmpty(ageArr)) {
				return ArrayUtil.join(Arrays.stream(ageArr).map(v -> allTtActioninterestNames.get(String.format("%s:%s", v,
						ToutiaoActionInterestEnum.ACTIONWORDS.getType()))).filter(v -> StringUtils.isNotBlank(v)).toArray(), Constants.COMMA);
			} else {
				return Constants.EMPTTYSTR;
			}
		} catch (Exception e) {
			return Constants.EMPTTYSTR;
		}
	}

	private String converGdtActionWords(String actionWords) {
		try {
			String[] ageArr = JSON.parseObject(actionWords, String[].class);
			//TODO 获取人群定向包的关联信息   gdt_dynamic_wordpack
			if (ArrayUtil.isNotEmpty(ageArr)) {
				return ArrayUtil.join(Arrays.stream(ageArr).filter(v -> StringUtils.isNotBlank(v)).toArray(), Constants.COMMA);
			} else {
				return Constants.EMPTTYSTR;
			}
		} catch (Exception e) {
			return Constants.EMPTTYSTR;
		}
	}

	private String converActionScene(String actionScene) {
		try {
			String[] ageArr = JSON.parseObject(actionScene, String[].class);
			if (ArrayUtil.isNotEmpty(ageArr)) {
				return ArrayUtil.join(Arrays.stream(ageArr).map(v -> ToutiaoActionSceneEnum.valueByType(v)).filter(v -> StringUtils.isNotBlank(v)).toArray(), Constants.COMMA);
			} else {
				return Constants.EMPTTYSTR;
			}
		} catch (Exception e) {
			return Constants.EMPTTYSTR;
		}
	}

	private String converAge(String ageArrJson) {
		try {
			String[] ageArr = JSON.parseObject(ageArrJson, String[].class);
			if (ArrayUtil.isNotEmpty(ageArr)) {
				return ArrayUtil.join(Arrays.stream(ageArr).map(v -> ToutiaoAgeEnum.valueByType(v)).filter(v -> StringUtils.isNotBlank(v)).toArray(), Constants.COMMA);
			} else {
				return Constants.EMPTTYSTR;
			}
		} catch (Exception e) {
			return Constants.EMPTTYSTR;
		}
	}

	private String converTtRetargetingTags(String retargetingTagsJson, Map<String, String> allTtPackThirdIdNames) {
		try {
			if (MapUtils.isEmpty(allTtPackThirdIdNames)) {
				return Constants.EMPTTYSTR;
			}
			String[] ageArr = JSON.parseObject(retargetingTagsJson, String[].class);
			//获取人群定向包的关联信息   tt_custom_audience
			if (ArrayUtil.isNotEmpty(ageArr)) {
				return ArrayUtil.join(Arrays.stream(ageArr).map(v -> allTtPackThirdIdNames.get(v)).filter(v -> StringUtils.isNotBlank(v)).toArray(), Constants.COMMA);
			} else {
				return Constants.EMPTTYSTR;
			}
		} catch (Exception e) {
			return Constants.EMPTTYSTR;
		}
	}

	private String converGdtRetargetingTags(String retargetingTagsJson, Map<String, String> allTtPackThirdIdNames) {

		try {
			if (MapUtils.isEmpty(allTtPackThirdIdNames)) {
				return Constants.EMPTTYSTR;
			}
			String[] ageArr = JSON.parseObject(retargetingTagsJson, String[].class);
			// 获取人群定向包的关联信息 gdt_audience_package
			if (ArrayUtil.isNotEmpty(ageArr)) {
				return ArrayUtil.join(Arrays.stream(ageArr).map(v -> allTtPackThirdIdNames.get(v)).filter(v -> StringUtils.isNotBlank(v)).toArray(), Constants.COMMA);
			} else {
				return Constants.EMPTTYSTR;
			}
		} catch (Exception e) {
			return Constants.EMPTTYSTR;
		}
	}
}
